package com.ttg.common.utils;

import com.ttg.common.exception.BaseException;
import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author huyangzou
 * @create 2020-12-18 18:34
 */
public class DateTimeUtil {

    private static final String PHP_DAYS_ADD_OR_SUB = "date\":\" *(today) *([\\-|\\+]) *([0-9]+) *(day) *\"";
    private static final String PHP_DAYS_ADD_OR_SUB_NO_DATE = "\" *(today) *([\\-|\\+]) *([0-9]+) *(day) *\"";
    private static final Pattern REG_PHP_DAYS_ADD_OR_SUB = Pattern.compile(PHP_DAYS_ADD_OR_SUB);
    private static final Pattern REG_PHP_DAYS_ADD_OR_SUB_NO_DATE = Pattern.compile(PHP_DAYS_ADD_OR_SUB_NO_DATE);

    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    private static final DateTimeFormatter formatterYYYY_MM_DD = DateTimeFormatter.ofPattern(YYYY_MM_DD);

    public static final String HH_MM = "HH:mm";
    private static final DateTimeFormatter formatterHH_MM = DateTimeFormatter.ofPattern(HH_MM);

    public static final String HH_MM_SS = "HH:mm:ss";
    private static final DateTimeFormatter formatterHH_MM_SS = DateTimeFormatter.ofPattern(HH_MM_SS);

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    private static final DateTimeFormatter formatterYYYY_MM_DD_HH_MM_SS = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    private static final DateTimeFormatter formatterYYYYMMDDHHMMSS = DateTimeFormatter.ofPattern(YYYYMMDDHHMMSS);

    public static final String YYYYMMDD = "yyyyMMdd";
    private static final DateTimeFormatter formatterYYYYMMDD = DateTimeFormatter.ofPattern(YYYYMMDD);

    public static final String MMddHHmmss = "MMddHHmmss";
    private static final DateTimeFormatter formatterMMddHHmmss = DateTimeFormatter.ofPattern(MMddHHmmss);

    public static final String YYYYMM = "yyyyMM";
    private static final DateTimeFormatter formatterYYYYMM = DateTimeFormatter.ofPattern(YYYYMM);

    public static final String YYYY = "yyyy";
    private static final DateTimeFormatter formatterYYYY = DateTimeFormatter.ofPattern(YYYY);
    //校验yyyyMMddHHmmss
    private static final String regexYYYYMMDDHHMMSS = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))([0-1]?[0-9]|2[0-3])([0-5][0-9])([0-5][0-9])$";
    //校验yyyyMMdd
    private static final String regexYYYYMMDD = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))$";
    //校验yyyy－MM－dd
    private static final String regexYYYY_MM_DD = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))$";
    //校验 yyyy-MM-dd HH:mm:ss
    private static final String regexYYYY_MM_DD_HH_MM_SS = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";


    private static final DateTimeFormatter RFC_3339 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS+08:00").withZone(ZoneId.of("Asia/Shanghai"));


    private static final DateTimeFormatter RFC_3339_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).optionalStart().appendOffset("+HH:MM:SS", "Z").optionalEnd().toFormatter();

    public static LocalDateTime rfc3339Str2LocalDateTime(String timeStr) {
        return ZonedDateTime.from(RFC_3339_DATE_TIME_FORMATTER.parse(timeStr)).toLocalDateTime();
    }

    public static String formatRfc3339(LocalDateTime dateTime) {
        return RFC_3339.format(dateTime);
    }

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static String formatYYYY_MM_DD_HH_MM_SS(LocalDateTime datetime) {
        return formatterYYYY_MM_DD_HH_MM_SS.format(datetime);
    }

    /**
     * yyyy-MM-dd
     */
    public static String formatYYYY_MM_DD(LocalDate date) {
        return formatterYYYY_MM_DD.format(date);
    }

    /**
     * 字符串转时间 yyyyMMddHHmmss  ->yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime strToYYYY_MM_DD_HH_mm_ss(String date) {
        return LocalDateTime.parse(date, formatterYYYYMMDDHHMMSS);
    }

    /**
     * 字符串转时间
     *
     * @param date 时间字符串 e.g. 14:00
     * @return
     */
    public static LocalTime strToHH_mm(String date) {
        return LocalTime.parse(date, formatterHH_MM);
    }

    /**
     * 时间转字符串
     *
     * @param date 14:00:30
     * @return
     */
    public static String hh_mm_ssToStr(LocalTime date) {
        return date.format(formatterHH_MM_SS);
    }

    /**
     * 字符串转时间
     *
     * @param date yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static LocalDateTime strToYYYY_MM_DD_HH_MM_SS(String date) {
        return LocalDateTime.parse(date, formatterYYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 字符串转时间
     *
     * @param date yyyy-MM-dd
     * @return
     */
    public static LocalDateTime strToYYYY_MM_DD(String date) {
        date += " 00:00:00";
        return LocalDateTime.parse(date, formatterYYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 交易结束时间
     */
    public static String getTimeExpire() {
        LocalDateTime expire = LocalDateTime.now().plus(10, ChronoUnit.MINUTES);
        return expire.format(formatterYYYYMMDDHHMMSS);
    }

    /**
     * 日期转YYYYMMDD
     */
    public static String formatYYYYMMDD(LocalDate date) {
        return formatterYYYYMMDD.format(date);
    }

    /**
     * 日期转YYYYMM
     */
    public static String formatYYYYMM(LocalDate date) {
        return formatterYYYYMM.format(date);
    }

    /**
     * 日期转YYYYMM
     */
    public static String formatYYYY(LocalDate date) {
        return formatterYYYY.format(date);
    }

    /**
     * 当前时间转 yyyyMMdd
     *
     * @return 20210201
     */
    public static String getNow() {
        return formatYYYYMMDD(LocalDate.now());
    }

    /**
     * 日期转YYYYMMDD
     * 20210201 -> 2021-02-01
     */
    public static LocalDate parseYYYYMMDD(String date) {
        return LocalDate.parse(date, formatterYYYYMMDD);
    }

    /**
     * 日期转YYYYMM
     * 202508 -> 2025-08
     */
    public static LocalDate parseYYYYMM(String yearMonth){
        return LocalDate.parse(yearMonth,formatterYYYYMM);
    }
    /**
     * 日期转YYYYMMDD
     */
    public static String formatDateTimeYYYYMMDD(LocalDateTime datetime) {
        return formatterYYYYMMDD.format(datetime);
    }

    /**
     * 日期转YYYYMMDD
     */
    public static String formatDateYYYYMMDD(LocalDate date) {
        return formatterYYYYMMDD.format(date);
    }


    /**
     * 字符串转时间 localDate
     */
    public static LocalDate strToDateYYYY_MM_DD(String date) {
        return LocalDate.parse(date, formatterYYYY_MM_DD);
    }

    /**
     * 比较日期相差秒数 temporal1 > temporal2 返回负值
     *
     * @param temporal1
     * @param temporal2
     * @return
     */
    public static long betweenSeconds(Temporal temporal1, Temporal temporal2) {
        return ChronoUnit.SECONDS.between(temporal1, temporal2);
    }

    /**
     * 获取当前时间的秒数 返回10位
     *
     * @return
     */
    public static long currentTimeSeconds() {
        return LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

    /**
     * 时间戳 秒 转LocalDateTime类型
     *
     * @param time 10位时间戳（秒）
     * @return
     */
    public static LocalDateTime parseSecondsTime(long time) {
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(time), ZoneId.systemDefault());
    }

    /**
     * 检查日期格式 yyyy-MM-dd,yyyyMMdd
     *
     * @param dataStr
     * @param format
     * @return
     */
    public static boolean isLocalDateStr(String dataStr, String format) {
        boolean iv = true;
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(format.replace("y", "u")).withResolverStyle(ResolverStyle.STRICT);
        try {
            LocalDate.parse(dataStr, fmt);
        } catch (Exception e) {
            e.printStackTrace();
            iv = false;
        }
        return iv;
    }

    public static DateTimeFormatter checkDateFormatStr(String dataStr) {
        if (StringUtils.isBlank(dataStr)) {
            throw new BaseException("日期传入不能为空");
        }
        return Pattern.matches(regexYYYY_MM_DD, dataStr) ? formatterYYYY_MM_DD : Pattern.matches(regexYYYY_MM_DD_HH_MM_SS, dataStr) ? formatterYYYY_MM_DD_HH_MM_SS : Pattern.matches(regexYYYYMMDD, dataStr) ? formatterYYYYMMDD : Pattern.matches(regexYYYYMMDDHHMMSS, dataStr) ? formatterYYYYMMDDHHMMSS : null;

    }

    public static DateTimeFormatter checkDateFormatStrForTime(String dataStr) {
        if (StringUtils.isBlank(dataStr)) {
            throw new BaseException("日期传入不能为空");
        }
        return Pattern.matches(regexYYYY_MM_DD_HH_MM_SS, dataStr) ? formatterYYYY_MM_DD_HH_MM_SS : Pattern.matches(regexYYYYMMDDHHMMSS, dataStr) ? formatterYYYYMMDDHHMMSS : null;

    }

    public static LocalDate parseDateFormatStr(String dataStr) {
        dataStr = convPHPDate(dataStr);
        DateTimeFormatter formater = checkDateFormatStr(dataStr);
        if (Objects.isNull(formater)) {
            throw new BaseException("LocalDate 日期格式不正确，请注意核对");
        }
        return LocalDate.parse(dataStr, formater);
    }

    public static LocalDateTime parseDateFormatStrForTime(String dataStr) {
        DateTimeFormatter formater = checkDateFormatStrForTime(dataStr);
        if (Objects.isNull(formater)) {
            if (Objects.nonNull(formater = checkDateFormatStr(dataStr))) {
                return DateTimeUtil.getTime000(LocalDate.parse(dataStr, formater));
            }
            throw new BaseException(" LocalDateTime 日期格式不正确，请注意核对");
        }
        return LocalDateTime.parse(dataStr, formater);
    }

    /**
     * 日期转 YYYYMMDDHHMMSS
     */
    public static String formatYYYYMMDDHHMMSS(LocalDateTime date) {
        return formatterYYYYMMDDHHMMSS.format(date);
    }

    /**
     * @param timeStr   20220607152420
     * @return  LocalDateTime
     */
    public static LocalDateTime strToYYYYMMDDHHMMSS(String timeStr){
        return LocalDateTime.parse(timeStr,formatterYYYYMMDDHHMMSS);
    }


    /**
     * 获取传入时间 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getTime000(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN);
    }

    /**
     * 获取传入时间 23时59分59秒的时间
     *
     * @return
     */
    public static LocalDateTime getTime235959(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.of(23,59,59));
    }

    /**
     * 获取当前日期 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getToday000() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
    }

    /**
     * 获取当前日期 23时59分59秒的时间
     *
     * @return
     */
    public static LocalDateTime getToday235959() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.of(23,59,59));
    }

    /**
     * 获取当前日期后一天 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getTomorrow000() {
        return getTomorrow000(LocalDate.now());
    }

    /**
     * 获取指定日期后一天 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getTomorrow000(LocalDate now) {
        return LocalDateTime.of(now.plusDays(1), LocalTime.MIN);
    }

    /**
     * 获取当前日期前一天 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getYesterday000() {
        return getYesterday000(LocalDate.now());
    }

    /**
     * 获取指定日期前一天 0时0分0秒的时间
     *
     * @return
     */
    public static LocalDateTime getYesterday000(LocalDate now) {
        return LocalDateTime.of(now.minusDays(1), LocalTime.MIN);
    }


    /**
     * 获取当前时间所在周的周一0分0秒
     *
     * @param now 当前时间
     * @return
     */
    public static LocalDateTime getFirstDayOnWeek(LocalDateTime now) {
        return LocalDateTime.of(now.toLocalDate().with(WeekFields.of(Locale.CHINA).dayOfWeek(), 1L).plusDays(1L), LocalTime.MIN);
    }

    /**
     * 获取当前时间所在周的周日23:59:59
     *
     * @param now 当前时间
     * @return
     */
    public static LocalDateTime getLastDayOnWeek(LocalDateTime now) {
        return LocalDateTime.of(now.toLocalDate().with(WeekFields.of(Locale.CHINA).dayOfWeek(), 7L).plusDays(1L), LocalTime.of(23,59,59));
    }

    /**
     * 获取当前时间所在月的第一天0分0秒
     *
     * @param now 当前时间
     * @return
     */
    public static LocalDateTime getFirstDayOnMonth(LocalDateTime now) {
        return LocalDateTime.of(now.toLocalDate().with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
    }

    /**
     * 获取当前时间所在月的最后一天23:59:59
     *
     * @param now 当前时间
     * @return
     */
    public static LocalDateTime getLastDayOnMonth(LocalDateTime now) {
        return LocalDateTime.of(now.toLocalDate().with(TemporalAdjusters.lastDayOfMonth()), LocalTime.of(23,59,59));
    }

    /**
     * 获取给的年月第一天
     * @param year 给定年
     * @param month 给定月
     * @return
     */
    public static int getFirstDayOnMonth(String year,String month) {
        if(StringUtils.isBlank(year) || StringUtils.isBlank(month)){
            throw new BaseException("给定年月不能为空");
        }
        LocalDate date = LocalDate.of(Integer.parseInt(year), Integer.parseInt(month), 1);
        return Integer.parseInt(formatDateYYYYMMDD(date));
    }

    /**
     * 获取当前时间所在月的最后一天
     * @param year 给定年
     * @param month 给定月
     * @return
     */
    public static int getLastDayOnMonth(String year,String month) {
        if(StringUtils.isBlank(year) || StringUtils.isBlank(month)){
            throw new BaseException("给定年月不能为空");
        }
        LocalDate date = YearMonth.of(Integer.parseInt(year), Integer.parseInt(month)).atEndOfMonth();
        return Integer.parseInt(formatDateYYYYMMDD(date));
    }

    /**
     * 获取当年第一天
     * @param year 给定年
     * @return: int
     */
    public static int getFirstDayOnYear(String year){
        LocalDate firstDay = LocalDate.of(Integer.valueOf(year), 1, 1);
        return Integer.parseInt(formatDateYYYYMMDD(firstDay));
    }

    /**
     * 获取起止年月间隔天数
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return: int
     */
    public static int daysBetween(String startDate, String endDate) {
        if(StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)){
            throw new BaseException("给定日期不能为空");
        }

        LocalDate d1 = LocalDate.of(Integer.parseInt(startDate.substring(0,4)), Integer.parseInt(startDate.substring(4,6)), Integer.parseInt(startDate.substring(6,8)));
        LocalDate d2 = LocalDate.of(Integer.parseInt(endDate.substring(0,4)), Integer.parseInt(endDate.substring(4,6)), Integer.parseInt(endDate.substring(6,8)));
        return (int) Math.abs(ChronoUnit.DAYS.between(d1, d2));
    }

    public static String getYear(LocalDate date){
        return String.valueOf(date.getYear());
    }

    public static String getMonth(LocalDate date){
        return String.valueOf(date.getMonthValue());
    }

    /**
     * MMddHHmmss
     */
    public static String formatMMDDHHMMSS(LocalDateTime datetime) {
        return formatterMMddHHmmss.format(datetime);
    }


    public static LocalDate strToLocaldate(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        if (!com.ttg.common.utils.StringUtil.checkYear(dateStr)) {
            return null;
        }
        return DateTimeUtil.strToDateYYYY_MM_DD(dateStr);
    }

    /**
     * @param timeStr yyyy-mm-dd hh:ii:sss   2019-11-19 15:16:17
     * @param format  1 20191119
     *                2 2019-11-19
     *                3 20191119151617
     * @return timeString
     */
    public static String localDateTimeToYmd(String timeStr, Integer format) {
        LocalDateTime dt = LocalDateTime.parse(timeStr, formatterYYYY_MM_DD_HH_MM_SS);
        if (1 == format) {
            return formatYYYYMMDD(dt.toLocalDate());
        }
        if (2 == format) {
            return formatYYYY_MM_DD(dt.toLocalDate());
        }
        if (3 == format) {
            return formatYYYYMMDDHHMMSS(dt);
        }
        return null;
    }

    public static Long getSecondFromTime(LocalDateTime time) {
        //获取秒数
        return time.toEpochSecond(ZoneOffset.of("+8"));
    }


    public static Long getMilliSecondFromTime(LocalDateTime time) {
        //获取毫秒数
        return time.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }


    public static boolean atDay(LocalDateTime time, LocalDate day) {
        return time.toLocalDate().isEqual(day);
    }


    public static boolean atToDay(LocalDateTime time) {
        return time.toLocalDate().isEqual(LocalDate.now());
    }

    /**
     * 获取${date} 前后 ${days}的时间
     *
     * @param date 指定日期
     * @param days 前后多少天，正表示之后，负表示之前
     * @return
     */
    public static LocalDate getAfterOrBeforeDay(LocalDate date, long days) {
        return date.plusDays(days);

    }

    public static String convPHPDate(String phpDate) {
        phpDate = phpDate.toLowerCase(Locale.ROOT);
        switch (phpDate) {
            case "today":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getToday000().toLocalDate());
            case "yesterday":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getYesterday000().toLocalDate());
            case "+1 day last sunday":
            case "this week":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getFirstDayOnWeek(LocalDateTime.now()).toLocalDate());
            case "last monday":
            case "last week":
                return DateTimeUtil.formatYYYY_MM_DD(LocalDate.now().minusDays(7).with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(1));
            case "last sunday":
                return DateTimeUtil.formatYYYY_MM_DD(LocalDate.now().minusDays(7).with(TemporalAdjusters.next(DayOfWeek.MONDAY)).minusDays(1));
            case "first day of this month":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getFirstDayOnMonth(LocalDateTime.now()).toLocalDate());
            case "first day of last month":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getFirstDayOnMonth(DateTimeUtil.getYesterday000(DateTimeUtil.getFirstDayOnMonth(LocalDateTime.now()).toLocalDate())).toLocalDate());
            case "last day of last month":
                return DateTimeUtil.formatYYYY_MM_DD(DateTimeUtil.getLastDayOnMonth(DateTimeUtil.getYesterday000(DateTimeUtil.getFirstDayOnMonth(LocalDateTime.now()).toLocalDate())).toLocalDate());
            default:
                return phpDate;
        }
    }


    public static String phpDaysAddOrSub2Str(String phpDateStr, String today, String opt, String num, String day) {
        if (!"today".equals(today) || !"day".equals(day)) {
            return phpDateStr;
        }
        if ("-".equals(opt)) {
            return DateTimeUtil.formatYYYY_MM_DD(LocalDate.now().minusDays(Long.parseLong(num)));
        } else {
            return DateTimeUtil.formatYYYY_MM_DD(LocalDate.now().plusDays(Long.parseLong(num)));
        }
    }

    public static String localDateTimeToYYYY_MM_DD(LocalDateTime time) {
        return formatterYYYY_MM_DD.format(time);
    }
    public static String localDateTimeToYYYY_MM_DD_HH_MM_SS(LocalDateTime time) {
        return formatYYYY_MM_DD_HH_MM_SS(time);
    }

    // 1=周一, 2=周二, ..., 7=周日
    public static int dayToKey(DayOfWeek dow) {
        return dow.getValue(); // ISO: 周一起始 1~7
    }

    // 从基准时间偏移plusday天后取后面一周的时间 映射到map
    public static Map<Integer, LocalDateTime> weekStarts(LocalDateTime base, int plusday) {
        LocalDate mon = base.toLocalDate().plusDays(plusday);
        Map<Integer, LocalDateTime> map = new LinkedHashMap<>();
        for (int i = 0; i < 7; i++) {
            LocalDate d = mon.plusDays(i);
            map.put(dayToKey(d.getDayOfWeek()), d.atStartOfDay());
        }
        return map;
    }

    public static LinkedHashMap<String, LocalDateTime> monthStarts(LocalDateTime base, int plusday) {
        LocalDate mon = base.toLocalDate().plusDays(plusday);
        LinkedHashMap<String, LocalDateTime> map = new LinkedHashMap<>();
        for (int i = 0; i < 31; i++) {
            LocalDate d = mon.plusDays(i);
            map.put(String.valueOf(d.getDayOfMonth()), d.atStartOfDay());
        }
        return map;
    }



    private static String[]  phpDates = "\"today\",\"yesterday\",\"+1 day last sunday\",\"this week\",\"last monday\",\"last week\",\"last sunday\",\"first day of this month\",\"first day of last month\",\"last day of last month\"".split(",");
    private static String[] phpDates2 = "today,yesterday,+1 day last sunday,this week,last monday,last week,last sunday,first day of this month,first day of last month,last day of last month".split(",");

    public static void main(String[] args) {


        String dayStr = "\"2023-02-27 00:00:00\"";

        System.out.println(replacePHPDateStrNoDaye(dayStr));


        // System.out.println(replacePHPDateStr("\"i\"sdate\" :\"today\",\" edate\":   \"today\",\"shop_no\"  : \"75\"3\""));
        // System.out.println(replacePHPDateStr("\"today\",\"yesterday\",\"+1 day last sunday\",\"this week\",\"last monday\",\"last week\",\"last sunday\",\"first day of this month\",\"first day of last month\",\"last day of last month\""));
        // System.out.println("today：" + convPHPDate("today"));
        // System.out.println("yesterday：" + convPHPDate("yesterday"));
        // System.out.println("+1 day last sunday：" + convPHPDate("+1 day last sunday"));
        // System.out.println("this week：" + convPHPDate("this week"));
        // System.out.println("last monday：" + convPHPDate("last monday"));
        // System.out.println("last week：" + convPHPDate("last week"));
        // System.out.println("last sunday：" + convPHPDate("last sunday"));
        // System.out.println("first day of this month：" + convPHPDate("first day of this month"));
        // System.out.println("first day of last month：" + convPHPDate("first day of last month"));
        // System.out.println("last day of last month：" + convPHPDate("last day of last month"));

        System.out.println(getYear(LocalDate.now()));
        System.out.println(getMonth(LocalDate.now()));
        System.out.println(hh_mm_ssToStr(LocalTime.of(12,10,30)));
    }

    public static String replacePHPDateStrNoDaye(String dataStr) {
        if (StringUtils.isBlank(dataStr)) {
            return dataStr;
        }
        for (int i = 0; i < phpDates.length; i++) {
            dataStr = dataStr.replace( phpDates[i], "\"" + convPHPDate(phpDates2[i]) + "\"");
        }
        Matcher matcher = REG_PHP_DAYS_ADD_OR_SUB_NO_DATE.matcher(dataStr);
        while (matcher.find()) {
            dataStr = dataStr.replace(matcher.group(0), "\"" + phpDaysAddOrSub2Str(matcher.group(0), matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4)) + "\"");
        }

        return dataStr;

    }

    public static String replacePHPDateStr(String dataStr) {
        if (StringUtils.isBlank(dataStr)) {
            return dataStr;
        }
        dataStr = dataStr.replaceAll(" *: *", ":");
        for (int i = 0; i < phpDates.length; i++) {
            dataStr = dataStr.replace("date\":" + phpDates[i], "date\":\"" + convPHPDate(phpDates2[i]) + "\"");
        }
        Matcher matcher = REG_PHP_DAYS_ADD_OR_SUB.matcher(dataStr);
        while (matcher.find()) {
            dataStr = dataStr.replace(matcher.group(0), "date\":\"" + phpDaysAddOrSub2Str(matcher.group(0), matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4)) + "\"");
        }

        return dataStr;

    }


    public static int daysOfYear(LocalDate date) {
        return date.getDayOfYear();
    }

    public static int allDaysOfYear(LocalDate date) {
        return date.with(TemporalAdjusters.lastDayOfYear()).getDayOfYear();
    }

    public static int daysOfQuarter(LocalDate date) {
        Month firstMonthOfQuarter = date.getMonth().firstMonthOfQuarter();
        LocalDate firstDayOfQuarter = LocalDate.of(date.getYear(), firstMonthOfQuarter, 1);
        return Math.toIntExact(firstDayOfQuarter.until(date, ChronoUnit.DAYS) + 1);
    }

    public static int allDaysOfQuarter(LocalDate date) {
        Month firstMonthOfQuarter = date.getMonth().firstMonthOfQuarter();
        LocalDate firstDayOfQuarter = LocalDate.of(date.getYear(), firstMonthOfQuarter, 1);
        LocalDate lastDayOfQuarter = LocalDate.of(date.getYear(), firstMonthOfQuarter.plus(2), firstMonthOfQuarter.plus(2).length(date.isLeapYear()));
        return Math.toIntExact(firstDayOfQuarter.until(lastDayOfQuarter, ChronoUnit.DAYS) + 1);
    }

    public static int daysOfMonth(LocalDate date) {
        return date.getDayOfMonth();
    }

    public static int allDaysOfMonth(LocalDate date) {
        return date.getMonth().length(date.isLeapYear());
    }

    public static int daysOfWeek(LocalDate date) {
        return date.getDayOfWeek().getValue();
    }

    public static int allDaysOfWeek(LocalDate date) {
        return 7;
    }
}
